package cn.stylefeng.guns.modular.fin.service;

import cn.stylefeng.guns.core.exceptions.UpdateDataException;
import cn.stylefeng.guns.modular.base.state.Constant;
import cn.stylefeng.guns.modular.base.state.F;
import cn.stylefeng.guns.modular.base.state.ProConst;
import cn.stylefeng.roses.core.reqres.response.ResponseData;
import cn.stylefeng.roses.core.reqres.response.SuccessResponseData;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.stylefeng.guns.core.common.page.LayuiPageFactory;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import cn.stylefeng.guns.modular.fin.entity.FinMining;
import cn.stylefeng.guns.modular.fin.mapper.FinMiningMapper;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;

/**
 * 矿机账户Service
 *
 * @author yaying.liu
 * @since 2022-06-07 13:37:29
 */
@Service
public  class FinMiningService extends ServiceImpl<FinMiningMapper,FinMining>{
    @Autowired
    private ScheduledExecutorService scheduledExecutorService;

    @Autowired
    private CurrencyService currencyService;

    @Resource
    private TransactionTemplate transactionTemplate;
    /**
     * 新增挖矿
     * @param memberId
     * @param usedPrice
     * @param lockedPrice
     * @param type
     * @param endTime
     * @return
     */
    public Boolean addFinMining(Long memberId, BigDecimal usedPrice, BigDecimal lockedPrice, String type, LocalDateTime endTime){
        FinMining mining = new FinMining();
        mining.setMemberId(memberId);
        mining.setUsedPrice(usedPrice);
        mining.setLockedPrice(lockedPrice);
        mining.setType(type);
        mining.setEndTime(endTime);
        mining.setStatus(false);
        Boolean ok = baseMapper.insert(mining) >0;
        this.addMiningTask(mining);
        return ok;
    }


    public FinMining  getNoOverFinMining(Long memberId,String type){
        LambdaQueryWrapper<FinMining> lqw = new LambdaQueryWrapper<>();
        lqw.eq(FinMining::getMemberId,memberId);
        lqw.eq(FinMining::getStatus,false);
        lqw.eq(FinMining::getType,type);
        return this.getOne(lqw,false);

    }

    public List<FinMining> getNoOverFinMiningList(){
        LambdaQueryWrapper<FinMining> lqw = new LambdaQueryWrapper<>();
        lqw.eq(FinMining::getStatus,false);
        return this.list(lqw);

    }



    /**
    * 删除矿机账户
    */
    public void deleteFinMining(Long finMiningId) {
        FinMining entity=this.baseMapper.selectById(finMiningId);
        //将删除标志设置为Y，表示删除
        this.baseMapper.updateById(entity);
    }

    /**
    * 添加矿机账户
    */
    public void addFinMining(FinMining finMining) {
        this.baseMapper.insert(finMining);
    }

    public ResponseData edit(FinMining finMining) {
        {
            FinMining walletQ = this.getById(finMining.getMiningId());
            if (walletQ != null)
            {
                if (!this.updateById(finMining))
                    throw new UpdateDataException(100);
                String coin = walletQ.getType();

                if (finMining.getUsedPrice().compareTo(walletQ.getUsedPrice()) > 0)
                {

                    //后台增加
                    F.me().saveCashflow(walletQ.getMemberId(), ProConst.WalletBigType.MINING, ProConst.CashFlowOpEnum.FLOW_IN, ProConst.CashFlowTypeEnum.PLATFORM_ADD,
                            finMining.getUsedPrice().subtract(walletQ.getUsedPrice()), coin,
                            finMining.getUsedPrice().subtract(walletQ.getUsedPrice()), coin,
                            BigDecimal.ZERO, coin,
                            ProConst.ItemCode.USED, coin, null, null,
                            walletQ.getUsedPrice(), finMining.getUsedPrice(), Constant.SYS_PLATFORM, walletQ.getMemberId());
                }
                if (finMining.getUsedPrice().compareTo(walletQ.getUsedPrice()) < 0)
                {
                    //后台减少
                    F.me().saveCashflow(walletQ.getMemberId(), ProConst.WalletBigType.MINING, ProConst.CashFlowOpEnum.FLOW_OUT, ProConst.CashFlowTypeEnum.PLATFORM_SUB,

                            walletQ.getUsedPrice().subtract(finMining.getUsedPrice()), coin,
                            walletQ.getUsedPrice().subtract(finMining.getUsedPrice()), coin,
                            BigDecimal.ZERO, coin,
                            ProConst.ItemCode.USED, coin, null, null,
                            walletQ.getUsedPrice(), finMining.getUsedPrice(), walletQ.getMemberId(), Constant.SYS_PLATFORM);
                }
            }
            return new SuccessResponseData();
        }
    }

    /**
     * 新增挖矿任务
     * @return
     */
    public Boolean addMiningTask(FinMining finMining){

        // 获取当前时间
        LocalDateTime now = LocalDateTime.now();
        // 计算当前时间与目标时间的时间差（以毫秒为单位）
        long delay = finMining.getEndTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() -
                now.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
        // 如果延迟时间为正数，则任务被延迟执行
        if (delay < 0) {
            delay = 0;
        }

      //  delay = 60000;

        scheduledExecutorService.schedule(() -> {
            System.out.println("挖矿结算: " + LocalDateTime.now());
            transactionTemplate.execute(e->{
              Boolean ok =  currencyService.unLockCurrencyReleasePledgeNum(finMining.getMemberId(),finMining.getType(),finMining.getLockedPrice(),"挖矿结算");
              if(ok){
                  ok =  currencyService.operateCurrencyUsedPrice(finMining.getMemberId(),"BTX", ProConst.CashFlowOpEnum.FLOW_IN,finMining.getUsedPrice(),"挖矿结算");
              }
              if(ok){
                  finMining.setStatus(true);
                  this.updateById(finMining);
              }else {
                  e.setRollbackOnly();
              }
                return ok;
            });

        }, delay, TimeUnit.MILLISECONDS);
        return true;
    }



    /**
     * 查询币币账户
     */
    public Page<Map<String, Object>> selectByCondition(Double minPrice,Double maxPrice,String condition,Long memberId,String recommendIds)
    {
        Page page = LayuiPageFactory.defaultPage();
        return this.baseMapper.selectByCondition(page,minPrice,maxPrice, condition,memberId,recommendIds);
    }



    public Boolean isMining(Long memberId, LocalDate date){
        LambdaQueryWrapper<FinMining> lqw = new LambdaQueryWrapper<>();
        lqw.eq(FinMining::getMemberId,memberId);
        lqw.ge(FinMining::getEndTime,date);
        return this.count(lqw) >0;
    }



}
